package com.gengzp.common.config;

import io.lettuce.core.ClientOptions;
import io.lettuce.core.SocketOptions;
import io.lettuce.core.TimeoutOptions;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

/**
 * Redis配置类（优化版：增强连接池和超时配置）
 */
@Configuration
public class RedisConfig {

    private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);

    // 从yaml读取的基础参数
    @Value("${spring.data.redis.host}")
    private String redisHost;

    @Value("${spring.data.redis.port}")
    private int redisPort;

    @Value("${spring.data.redis.password}")
    private String redisPassword;

    @Value("${spring.data.redis.database}")
    private int redisDatabase;

    @Value("${spring.data.redis.timeout:5000}")
    private int redisTimeout; // 毫秒

    // 连接池参数（从yaml读取）
    @Value("${spring.data.redis.lettuce.pool.max-active:32}")
    private int poolMaxActive;

    @Value("${spring.data.redis.lettuce.pool.max-idle:16}")
    private int poolMaxIdle;

    @Value("${spring.data.redis.lettuce.pool.min-idle:8}")
    private int poolMinIdle;

    @Value("${spring.data.redis.lettuce.pool.max-wait:5000}")
    private long poolMaxWait; // 毫秒

    // 自定义的优化参数
    private static final int MIN_EVICTABLE_IDLE_TIME = 60000; // 1分钟
    private static final int TIME_BETWEEN_EVICTION_RUNS = 30000; // 30秒
    private static final int NUM_TESTS_PER_EVICTION_RUN = 3;
    private static final boolean TEST_WHILE_IDLE = true;
    private static final boolean TEST_ON_BORROW = true;
    private static final boolean TEST_ON_RETURN = false;
    private static final boolean LIFO = false;
    private static final boolean BLOCK_WHEN_EXHAUSTED = true;

    /**
     * Redis连接工厂（优化版）
     */
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        logger.info("开始初始化Redis连接工厂，配置: host={}, port={}, db={}, timeout={}ms",
                redisHost, redisPort, redisDatabase, redisTimeout);

        // 基础连接配置
        RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
        redisConfig.setHostName(redisHost);
        redisConfig.setPort(redisPort);
        redisConfig.setPassword(redisPassword);
        redisConfig.setDatabase(redisDatabase);

        // Socket选项优化
        SocketOptions socketOptions = SocketOptions.builder()
                .connectTimeout(Duration.ofSeconds(10)) // 增加连接超时时间
                .keepAlive(true) // 启用TCP keepalive
                .build();

        // 客户端选项配置
        ClientOptions clientOptions = ClientOptions.builder()
                .socketOptions(socketOptions)
                .autoReconnect(true) // 启用自动重连
                .pingBeforeActivateConnection(true) // 激活前ping检测
                .timeoutOptions(TimeoutOptions.builder()
                        .fixedTimeout(Duration.ofSeconds(10)) // 固定超时时间
                        .build())
                .build();

        // 优化的连接池配置
        GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();

        // 基础池参数
        poolConfig.setMaxTotal(poolMaxActive);
        poolConfig.setMaxIdle(poolMaxIdle);
        poolConfig.setMinIdle(poolMinIdle);
        poolConfig.setMaxWait(Duration.ofMillis(poolMaxWait));

        // 连接有效性检测配置
        poolConfig.setTestOnBorrow(TEST_ON_BORROW);
        poolConfig.setTestOnReturn(TEST_ON_RETURN);
        poolConfig.setTestWhileIdle(TEST_WHILE_IDLE);
        poolConfig.setTimeBetweenEvictionRuns(Duration.ofMillis(TIME_BETWEEN_EVICTION_RUNS));
        poolConfig.setMinEvictableIdleTime(Duration.ofMillis(MIN_EVICTABLE_IDLE_TIME));
        poolConfig.setNumTestsPerEvictionRun(NUM_TESTS_PER_EVICTION_RUN);
        poolConfig.setLifo(LIFO);
        poolConfig.setBlockWhenExhausted(BLOCK_WHEN_EXHAUSTED);

        // 连接池健康检查
        poolConfig.setTestOnCreate(true);

        // 客户端资源配置
        ClientResources clientResources = DefaultClientResources.builder()
                .ioThreadPoolSize(Math.max(4, Runtime.getRuntime().availableProcessors()))
                .computationThreadPoolSize(Math.max(4, Runtime.getRuntime().availableProcessors()))
                .build();

        // Lettuce连接池配置
        LettucePoolingClientConfiguration lettuceConfig = LettucePoolingClientConfiguration.builder()
                .clientOptions(clientOptions)
                .clientResources(clientResources)
                .poolConfig(poolConfig)
                .commandTimeout(Duration.ofSeconds(10)) // 增加命令超时时间
                .build();

        // 创建连接工厂
        LettuceConnectionFactory factory = new LettuceConnectionFactory(redisConfig, lettuceConfig);
        factory.afterPropertiesSet();

        logger.info("Redis连接工厂初始化完成，host: {}, port: {}, db: {}",
                redisHost, redisPort, redisDatabase);

        return factory;
    }

    /**
     * 自定义RedisTemplate（优化序列化配置）
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // 设置序列化器
        GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
        RedisSerializer<String> stringSerializer = RedisSerializer.string();

        template.setKeySerializer(stringSerializer);
        template.setHashKeySerializer(stringSerializer);
        template.setValueSerializer(jsonSerializer);
        template.setHashValueSerializer(jsonSerializer);

        // 启用事务支持
        template.setEnableTransactionSupport(false);

        template.afterPropertiesSet();
        logger.info("RedisTemplate初始化完成");

        return template;
    }

}



